﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Gwn.Library.MvpVm.Security
{
    /// <summary>
    /// Code from:
    /// DavideZordan.net - http://www.davidezordan.net/blog/?p=202 
    /// Using the AES algorithm to encrypt/decrypt data in a Silverlight application
    /// </summary>
    public static class Hashing
    {
        /// <summary>
        /// Gets the hash key.
        /// </summary>
        /// <param name="hashKey">The hash key.</param>
        /// <param name="salt">The salt.</param>
        /// <returns></returns>
        public static byte[] GetHashKey(string hashKey, string salt)
        {
            // Initialise
            var encoder = new UTF8Encoding();

            // Get the salt
            byte[] saltBytes = encoder.GetBytes(salt);

            // Setup the hasher
            var rfc = new Rfc2898DeriveBytes(hashKey, saltBytes);

            // Return the key
            return rfc.GetBytes(16);
        }

        /// <summary>
        /// Encrypts the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="dataToEncrypt">The data to encrypt.</param>
        /// <returns></returns>
        public static string Encrypt(byte[] key, string dataToEncrypt)
        {
            // Initialise
            var encryptor = new AesManaged {Key = key, IV = key};

            // Set the key

            // create a memory stream
            using (var encryptionStream = new MemoryStream())
            {
                // Create the crypto stream
                using (var encrypt = new CryptoStream(encryptionStream, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    // Encrypt
                    byte[] utfD1 = Encoding.UTF8.GetBytes(dataToEncrypt);
                    encrypt.Write(utfD1, 0, utfD1.Length);
                    encrypt.FlushFinalBlock();
                    encrypt.Close();

                    // Return the encrypted data
                    return Convert.ToBase64String(encryptionStream.ToArray());
                }
            }
        }

        /// <summary>
        /// Decrypts the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="encryptedString">The encrypted string.</param>
        /// <returns></returns>
        public static string Decrypt(byte[] key, string encryptedString)
        {
            if (string.IsNullOrEmpty(encryptedString))
                return encryptedString;

            // Initialise
            var decryptor = new AesManaged();
            byte[] encryptedData = Convert.FromBase64String(encryptedString);

            // Set the key
            decryptor.Key = key;
            decryptor.IV = key;

            // create a memory stream
            using (var decryptionStream = new MemoryStream())
            {
                // Create the crypto stream
                using (var decrypt = new CryptoStream(decryptionStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    // Encrypt
                    decrypt.Write(encryptedData, 0, encryptedData.Length);
                    decrypt.Flush();
                    decrypt.Close();

                    // Return the unencrypted data
                    byte[] decryptedData = decryptionStream.ToArray();
                    return Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
                }
            }
        }
    }
}
